Skip to main content

skip to main content

developerWorks  >  Power Architecture technology  >

Testing and measuring the TAMS 3011, Part 2: An introduction to eCos

You must become one with the kernel

developerWorks
Document options

Document options requiring JavaScript are not displayed


Rate this page

Help us improve this content


Level: Introductory

Peter Seebach (developerworks@seebs.plethora.net), Freelance author, Plethora.net

24 Feb 2006

The eCos embedded operating system offers an alternative to UNIX®-style operating systems for development work. This article examines how its architecture influences the development process, building a sample application and exploring the differences in architecture between eCos and UNIX.

The eCos embedded operating system is closer in design to embedded systems such as VxWorks than to embedded Linux®. In the UNIX environment, the operating system (OS) provides services to separate programs which run under it. By contrast, an eCos program contains both the entire OS and the target application. While the application can be multithreaded, only one application can run on the system at a given time.

With this overview, we can start talking about what it takes to build a real application on eCos. You can't just load up a Web server, perl, and some CGI scripts; you have to build everything as a single executable.

The key distinction is address space. In UNIX systems, the kernel has its own address space, which applications don't have access to, and each application can (and most do) have separate address spaces. eCos only has one address space. Similarly, each program on the UNIX system is a separate file, while with eCos, there is only one monolithic file.

In both cases, the OS code configures hardware and sets up device drivers, then provides services to applications. In eCos, the library code can call driver code directly, rather than needing to pass instructions to a separate kernel. Under UNIX-like systems, the kernel runs a process (usually init) which then launches other processes; under eCos, the kernel runs a user-provided main function which may, if it wants, run multiple threads.

This linking architecture increases the apparent size of an application; while a native Linux "hello, world!" application might only be 4KB, a "hello, world!" eCos application for the TAMS 3011 came out to about 326KB. On the other hand, on eCos, that included the whole kernel; if you add in the initrd filesystem image, the kernel, and the C library, the code used to perform the task on Linux is closer to 4.5MB.

The eCos system is open source, currently distributed under a slightly modified version of the GPL. The modification creates an exemption for programs linked with eCos that creates the same effect you get from running a program under Linux; you are not required to release your program's source, but you still have to release modifications to the eCos source. It is available for free, and is royalty-free regardless of the number of developers or the number of shipping products you make based on it.

How eCos works

For the UNIX users out there, a little bit more detail of how an embedded OS like eCos works might be in order. In the UNIX environment, the OS runs directly on the hardware. The OS loads programs, which then communicate with it by means of system calls. By contrast, library services are linked into the program; library services, although distributed with the OS, run in the user program's address space, and use the same system calls the user's code would to access OS services. (In fact, you can omit the libraries, and just work directly with system calls, but it would generally be silly to do that.)

The OS allocates memory space and loads programs from any arbitrary storage medium into this memory. These programs access OS services by means of "syscalls" (semantically the equivalent of BIOS and DOS INT calls from the bad old days). In practice, it is neither necessary nor desirable to expose the syscall mechanism directly to application code, so applications talk to the OS through a library that translates requests from the application layer into syscalls. The usual such library employed in general-purpose Linux systems is glibc, which is a very large beast indeed; see Resources for a reference on stripping it down somewhat.

Other library services, not inherently part of the OS, are provided either through "shared objects" (dynamically linked libraries - a single copy of the library is shared by all applications that require its functionality), or by the developer of a program choosing to link statically with a given library at build time.

One way to think of eCos is to see it as the kernel just being linked in as a particularly large and complete library. In fact, this is exactly how the build process works; a library is built, and your code is linked against it. Rather than system calls being made to a separate program, they're just regular function calls within a single large executable.

The exact set of features provided is up to the user. You can include only the features you actually need, or you can include the entire operating system. The ability to omit features you aren't using can help save space. On the sample "hello, world" program, a reasonably complete build is about 2MB, even though the stripped executable is only 326KB. For applications designed to run on smaller embedded boards, this is very useful.

While Linux systems allow a certain amount of granularity in configuration, it's generally not nearly as fine-grained as the eCos configuration tool is. You can remove nearly every feature of eCos, and very few dependencies exist only because someone didn't want to maintain the code for running without a given feature. Some tweaks might give preference to RAM footprint, or to speed of execution. Many Linux features simply cannot be removed with the regular tools.

Similarly, eCos has excellent support for boot configuration built into the kernel; things that, on a Linux system, would be handled by the boot loader, are built into eCos as part of the kernel, so it can be a single self-contained image, to be run directly from flash or RAM.

An embedded system built on top of Linux will need enough memory to handle the kernel, some userland support programs (such as init), and the application; it will need a root filesystem with at least a few files in it, including configuration files and shells. An embedded system built on eCos needs only one hunk of data (the eCos application, including the kernel). This isn't to say you can't have more; some eCos systems have filesystem code and multiple files. It is, however, optional. You don't even need the hunk of data to be a file; it can just be a chunk of flash memory that the machine jumps to and begins executing.

Implementation notes

To get a feel for the development environment, start out with a simple "hello, world" program. The program's source is completely unexceptional:
Listing 1: "hello, world!"

	#include <stdio.h>
	int
	main(void) {
		printf("hello, world!\n");
		return 0;
	}

Building it requires a bit of preparation. The eCos build environment assumes that you will develop using a "build tree" to build the customized kernel library your application will be linked with. To start up, you need two things: the compiler toolchain and some eCos-specific tools in your PATH, and you need an eCos repository, set in the eponymous environment variable ECOS_REPOSITORY.

The eCos kernel is built in C++, and thus links directly with C or C++ code. The kernel is built by creating a configuration file, using the ecosconfig program. (You can also use a graphical interface, but I found the command line more comfortable; the interfaces sometimes have slightly different feature sets.) To create a new build routine, you run the command ecosconfig new target. For instance, for the TAMS 3011, the command is ecosconfig new moab405GPr. This brings in the drivers for that particular platform; kernel modules and features can be added with ecosconfig add feature. In many cases, the default set works fine.

Once you've picked a feature set, you create the build tree by running ecosconfig tree. This creates a compilation tree which uses the source in ECOS_REPOSITORY to build a local kernel; start the build by running make. Many build processes advise you to go make a cup of coffee during the build; unless you're on a pretty slow computer, you won't have time with eCos.

Building the application by hand is possible, but not worth the trouble; you can just use the provided build_Makefile script. In a new directory (for convenience, I recommend a sibling of the kernel tree), copy the build_Makefile and build_Make.params files from the eCos repository's examples directory; with the software package for the TAMS 3011, that's /opt/mlb/ecos/examples.

The build_Makefile script builds a Makefile suitable for compiling applications. The easiest way to use it is to pass it the variables SRCS and DST as environment variables, and the path to the custom kernel. For instance:


Listing 2. Running build_Makefile

	$ SRCS=main.c DST=main ./build_Makefile ../ecos_kernel
	$ make

In the software distribution I got, the build_Makefile script needed to be marked executable (chmod +x), and the resulting Make.params file specified the -finit-priority flag, which isn't supported by this release of gcc. No big deal; remove the flag, run make, and you have an executable.



Back to top


Running the executable

To run the executable, you have to load it on the target system, then execute it. On the TAMS 3011, this is done using RedBoot. In fact, RedBoot is another eCos application! If you don't need to flash your application into memory, it's painfully easy to load it. Just copy it into the tftp directory on your tftp server, and load it:


Listing 3. Loading and running an application

	RedBoot> lo main
	Using default protocol (TFTP)
	Entry point: 0x00080000, address range: 0x00080000-0x000beb9c
	RedBoot> go
	(boot messages)
	hello, world!

Note that the entry point doesn't need to be specified. The executable's header contains the information needed, and the boot loader can load it at the right place. I omitted the boot messages in the example, but my system has about 40 lines of them; these are messages from the eCos kernel code as it bootstraps the system, probes devices, and so on.

Note that you don't get your prompt back. This is not a program being run under another operating system; this is a new operating system being loaded and executed. Since the new operating system doesn't do very much, it's not very interesting to watch, but it establishes that the system is loading the code you wrote and executing it.

It is possible to do without the boot loader, flashing your application into a device to be loaded automatically by lower-level firmware, or to use a boot loader other than RedBoot. However, since RedBoot is an eCos application, if your target hardware supports eCos, it will also generally support RedBoot, which makes RedBoot an appealing choice. For more information about RedBoot, see Resources.



Back to top


Debugging

It is, of course, dimly conceivable that something will one day go wrong. Now, under UNIX, you attach a debugger to the process you want to debug. On a single-process system, you can't do this as easily. You can use hardware monitors, but in fact, if you build a default kernel configuration, you can do well enough just using gdb over the serial port.

Debugging remotely can be a little weird. It is absolutely crucial that the binary image you give to the debugger is the same image running on the target; if you use even slightly different binaries, you can get meaningless results. Because the libraries and kernel are all linked together, a mismatch can result in very confused behavior from the debugger. The documentation for the board mentions how to configure gdb to attach over a serial line. Look for a string like "$T0b40:000876a8;01:0012adc0;#7e"; this indicates that the system has stopped execution and is waiting for a debugger to guide it. When you see that, disconnect your terminal program and sic gdb on it.



Back to top


Adding and removing features

The eCos configuration system is very flexible and encourages tuning to remove unneeded drivers. You can add or remove single packages, and dependencies are checked. The eCos configuration file (typically called "ecos.ecc") contains a list of configuration flags and options, used by the ecosconfig tree command to generate a build tree targeting a specific platform and feature set.

To get a list of supported packages, use ecosconfig list. This lists packages, along with their aliases (short names you can use for them). For instance, the CYGPKG_IO_SERIAL package can also be referred to as just "serial":

Package CYGPKG_IO_SERIAL (Serial device drivers):
 aliases: serial io_serial
 versions: current

One reason to remove drivers would be to reduce size; another is to improve startup time. For instance, if you don't need both ethernet ports on the 3011, disabling a driver reduces the time spent booting. In fact, both can be removed for console-only activities. Removing drivers and software is reasonably straightforward, and the dependency checking will help you out, if you remove something without removing other things which depended on it. (Use ecosconfig check to verify your work.)

Debugger support is controlled separately, with the --enable-debug and --disable-debug options to ecosconfig.



Back to top


Doing something

One of the tests I've used with other embedded systems is seeing how easy it is to play Zork on a system. Zork, for those who have missed it, is a wonderful little text adventure, and getting it running is a good test for a platform. I've grown accustomed to the Zork test, and perhaps even a little complacent about it. On a generic embedded Linux, getting Zork running takes maybe half an hour of work. On eCos, actually getting Zork running turns out to take a bit of work, making it a good reminder of the point of the test: it helps you see what's built into a system and how complete the developer support is. Porting something to work on eCos takes a few steps, and you can go about it in a number of ways.

To get Zork running, the obvious program to port is a Z-machine interpreter. These generally use the curses library, which abstracts access to cursor-addressable terminals (thus the name). Curses is very useful, but it doesn't map well onto the typical uses of eCos, so it's not provided with the system. Getting curses ported turns out to be more interesting than you might think, because it depends heavily on termcap (or terminfo), which in turn depends on databases on disk.

The BSD curses library is dramatically smaller and somewhat simpler than ncurses, so it makes a better starting point. In the next article in this series, I'll show how to port Berkeley curses to eCos and test a simple curses application, and I'll show more of the ways in which curses tends to assume a full UNIX environment.



Resources

Learn

Get products and technologies

Discuss


About the author

Peter Seebach has been using Macs since the Macintosh SE, and thinks this is the cutest one ever. He denies that his Mac mini was ever lost in the couch. You can reach him at developerworks@seebs.plethora.net.




Rate this page


Please take a moment to complete this form to help us better serve you.



YesNoDon't know
 


 


12345
Not
useful
Extremely
useful
 


Back to top