Slimline Open Firmware - SLOF

Copyright (C) 2004, 2008  IBM Corporation


Index
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1.0 Introduction to Open Firmware
1.1 Build process
2.0 Extension
3.0 Limitations

1.0 Introduction to Open Firmware
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

The IEEE Standard 1275-1994 [1], Standard for Boot (Initialization Configuration)
Firmware, Core Requirements and Practices, is the first non-proprietary open
standard for boot firmware that is usable on different processors and buses.
Firmware which complies with this standard (also known as Open Firmware)
includes a processor-independent device interface that allows add-in devices
to identify itself and to supply a single boot driver that can be used,
unchanged, on any CPU.  In addition, Open Firmware includes a user interface
with powerful scripting and debugging support and a client interface that
allows an operating system and its loaders to use Open Firmware services
during the configuration and initialization process.  Open Firmware stores
information about the hardware in a tree structure called the
``device tree''.  This device tree supports multiple interconnected system
buses and offers a framework for ``plug and play''-type auto configuration
across different buses.  It was designed to support a variety of different
processor Instruction Set Architectures (ISAs) and buses.

The full documentation of this Standard can be found in [1].


1.1 Build process
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Open Firmware (OF) is based on the programming language Forth. 
SLOF use Paflof as the Forth engine, which was developed by
Segher Boessenkool.  Most parts of the Forth engine are implemented in 
C, by using GNU extensions of ANSI C, (e.g. assigned goto, often misnamed "computed goto"),
resulting in a very efficient yet still quite portable engine.  

The basic Forth words, so-called primitives,  are implemented with 
a set of C macros.  A set of .in and .code files are provided, which
define the semantic of the Forth primitives.  A Perl script translates 
these files into valid C code, which will be compiled into the Forth engine.
The complete Forth system composes of the basic Forth primitives and
a set of Forth words, which are compiled during the start of the Forth
system.

Example:
Forth primitive 'dup'

	dup ( a -- a a) \ Duplicate top of stack element


prim.in:	
	cod(DUP)

prim.code:
	PRIM(DUP) cell x = TOS; PUSH; TOS = x; MIRP

Generated code:

static cell xt_DUP[] = { { .a = xt_DOTICK }, { .c = "\000\003DUP" },
	 { .a = &&code_DUP }, };

code_DUP: { asm("#### " "DUP"); void *w = (cfa = (++ip)->a)->a;
	 cell x = (*dp); dp++; (*dp) = x; goto *w; }

Without going into detail, it can be seen, that the data stack is
implemented in C as an array of cells, where dp is the pointer to the top of
stack. 

For the implementation of the Open Firmware, most of the
code is added as Forth code and bound to the engine.  Also 
the system vector for reset and all kinds of exceptions
will be part of the image. Additionally a secondary boot-loader
or any other client application can be bound to the code as payload, 
e.g. diagnostics and test programs.

The Open Firmware image will be put together by the build 
process, with a loader at the start of the image. This loader
is called by Low Level Firmware and loads at boot time the Open 
Firmware to it's location in memory (see 1.3 Load process). Additionally 
a secondary boot loader or any other client application can be bound
to the code as payload.

The Low Level Firmware (LLFW) is responsible for setting up the 
system in an initial state. This task includes the setup of the 
CPUs, the system memory and all the buses as well as the serial port
itself.


2.0 Extension
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

In the following paragraphs it will be shown how to add
new primitive words (i.e., words implemented not by building
pre-existing Forth words together, but instead implemented in
C or assembler).  With this, it is possible to adapt SLOF to
the specific needs of different hardware and architectures.


To add primitives:
   
   For a new primitive, following steps have to be done:

   + Definition of primitive name in <arch>.in
     - cod(ABC) defines primitive ABC

     You can also use the following in a .in file, see existing
     code for how to use these:
     - con(ABC) defines constant ABC   
     - col(ABC) defines colon definition ABC
     - dfr(ABC) defines defer definition ABC

   + Definition of the primitives effects in <arch>.code
     - PRIM(ABC) ... MIRP

       The code for the primitive body is any C-code. With
       the macros of prim.code the data and return stack of 
       the Forth engine can be appropriately manipulated.


3.0 Limitations of this package
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 On a JS20 the memory setup is very static and therefore there are
 only very few combinations of memory DIMM placement actually work.

 Known booting configurations:

    * 4x 256 MB (filling all slots) -- only "0.5 GB" reported.
    * 2x 1 GB, slots 3/4 -- only "0.5 GB" reported.

 Known failing configurations

    * 2x 256 MB, slots 3/4
    * 2x 256 MB, slots 1/2

 On a JS20 SLOF wil always report 0.5 GB even if there is much more memory
 available.

 On a JS21 all memory configurations should work.

Documentation
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

[1] IEEE 1275-1994 Standard, Standard for Boot (Initialization Configuration)
    Firmware: Core Requierements and Practices

