Architecture#
The Phoenix-RTOS loader is a self-sufficient application which does not use any of the external libraries.
It only includes common syspage’s header files from phoenix-rtos-kernel.
Plo is divided into five subsystems:
cmds - command-line interface
devices - platform’s drivers
HAL - hardware abstraction layer
lib - common routines
phfs - phoenix filesystem
syspage - system configuration structure
Cmds#
Each of the commands has to implement interface defined in cmds/cmd.h
and be registered using constructor invocation.
There is a flexibility of defining command setups for each platform. The targets define their own set of commands in
PLO_COMMANDS
variable in a Makefile
file.
All available commands are described in the CLI chapter.
Devices#
Devices are the hardware dependent subsystem containing a collection of drivers with a unified interface for the other
loader components. Each driver has to register itself using constructor invocation. During bootloader initialization,
the registered devices are initialized and appropriate major.minor
numbers are assigned to them. The other plo’s
components refer to specific devices using major.minor
identification. The minor number indicates on the device
instance and is assigned dynamically. However, the major numbers are static and refer to the following device types:
0
- UART1
- USB2
- STORAGE3
- TTY
Each platform defines its own set of drivers in a Makefile
file.
HAL#
HAL (Hardware Abstraction Layer) is the loader hardware dependent subsystem used for adapting it to the particular hardware platform. It provides the unified interface for the other plo components. When loader is ported to the new architecture, only the common HAL interface has to be implemented, the rest of the subsystems remain unchanged.
HAL implements the following functionalities:
platform initialization
types definition
basic console
string functions
timer controller
exceptions and interrupts handling
memory synchronization
Platform initialization#
Platform initialization is one of the most important part of the loader. Typically, the majority of the code is
written in assembly language and is placed in a _init.S
file. It prepares the most low-level components of the
processor like cache invalidation, Flex RAM configuration, disabling MMU and FPU. After that, the loader moves to
platform specific controller initialization. In this part, the loader is responsible for setting clocks,
PLLs, external memory controllers like DDR and preparing other crucial components for dedicated platforms.
Console#
Console is used for presenting plo messages until the device driver for the console is initialized. It is typically based on UART, but it can use other display devices (on IA32 there is a console based on VGA graphics adapter and keyboard). Initially, the console should be kept as simple as possible, so it works from the early boot stage. It does not use interrupts or other HAL mechanisms, nor allow the loader to read data.
Strings#
HAL provides a set of string functions used for data copying and string manipulation. They correspond to ANSI C functions provided by the compiler, but the compiler’s functions are not intentionally used. The intention was to implement these functions from scratch to control the details of implementation and external references.
Timer#
The timer driver controller is a part of the common HAL interface. It calculates uptime from booting in milliseconds.
Interrupts & Exceptions#
HAL handles interrupts, implements the interrupt and exception stubs for specific architectures and service routines invocations.
Furthermore, interrupts interface provides synchronization mechanisms, it allows to either disable or enable interrupts in other loader’s subsystems.
Common routines#
Common routines contain the following units:
circular buffer
- basic interface to push and pop data to bufferconsole
- unit sets console to specific device and prints data on itset of functions to handle
character types
error definition
circular doubly-linked list
- basic interface to operate on listlogger
- log information with appropriate formattingfamily of
printf functions
variable arguments handling
PHFS#
PHFS (phoenix filesystem) is an abstraction for data access from different devices. This abstraction is used by CLI to copy data/files from different sources to physical memory maps. Currently, phfs supports two protocols for data access:
raw
- direct access to storage devicesphoenixd
- protocol to exchange data between host and target platform via interfaces like serial or USB, using Phoenix Daemon.
In order to use a device in the phoenix filesystem, the user should assign an alias to a dedicated major.minor
identification of the device with an appropriate protocol type, for example: phfs usb0 1.0 phoenixd
.
Syspage#
Low-level kernel initialization is based on syspage_t
structure. This structure is prepared during the bootstrap
process by the loader. It is stored on the physical memory at the address above the stack memory. The syspage_t
definition consists of the generic part which is common to all architectures and the hardware architecture dependent
data. Syspage provides information like physical memory maps, interrupts tables, preloaded user applications and data
for specific architecture. It should be treated as the main structure used for operating system configuration.