Menu

Home

Pharos Team

Welcome to Pharos!

Pharos is a Real-Time Operating System. Is provides the mechanisms typical of RTOSes (multi-threading, fixed-priority preemptive scheduler, semaphores, message queues, etc) but also some functionalities that are rare:

  • partitioning (think processes in Linux) with memory protection and also time protection
  • inter-partitioning communication/synchronization
  • prioritized nested interrupts
  • CPU dependent configuration, while Pharos provides a generic API that is common to all CPUs, we also allow you to configure your application according to the specific CPU capabilities (e.g. interrupt priority)
  • RMP (Real-time Multi-Processing) - a multicore implementation one step further than AMP, but one step back than SMP
  • static configuration - you can, at compile time, state the exact configuration of your app (e.g. which tasks, semaphores, etc)
  • dynamically memory - you can still allocate memory dynamically if you really need to
  • "lazy load" - this means that you can setup a partition to be initialized later on
  • native support for periodic, sporadic and aperiodic threads with deadline thread execution time monitoring and control
  • inter-partition calls - custom made functions where one partition may call functions of another partition
  • channel - a zero-copy, extremely fast way for a partition to communicate with another, even on a different CPU core
    -filters" - custom made application functions that allow (or not) inter-partition communication

See a quick presentation on https://www.slideshare.net/RTOSPharos/pharos-310

Objectives

Pharos was designed with the following systems in mind:

  • secure systems
  • safe systems
  • real-time systems

That is, we place security and safety (e.g. memory must protected) as top objectives. Then we consider real-time implications (e.g. determinism). Other objectives like speed, memory occupation are also important, but they are secondary.

Design

For the experts that understand the concepts of monolithic and micro-kernel, Pharos is designed following a micro-kernel paradigm. This is because security and safety are the most important aspects of Pharos. This means that applications using Pharos should feel confident that security breaches are difficult to occur given the design of Pharos. Also, given the nature of micro-kernels, they are, by design, intrinsically small. This makes them much easier to test and give a higher confidence that they don't have bugs or exploits.

No matter how perfect an OS is, a badly designed application can always produce errors. However, in Pharos a partition that has a inherent security issue will not be allowed to propagate that breach to other partitions (in terms of memory or time). Security is a major driver in placing Pharos as an open-source project: this allows it to be scrutinized by everyone. Security by obscurity is not the way to go (https://en.wikipedia.org/wiki/Security_through_obscurity).

Another objective relates to real-time systems. That is, systems where you want to know that even in the worst overload scenarios your system will behave as expected. With this goal, Pharos provides a fixed-priority preemptive scheduler for single-core and multi-core systems. Real-Time Operating Systems for single-core systems are wide spread and although Pharos does bring some improvements (for example, a very fast clock tick processing routine that only awakes the highest priority thread, as opposed to awakening all the threads that are supposed to - note that Pharos still behaves as expected), Pharos major improvements come in multi-core systems were an "RMP" (Real-time MultiProcessing) design was introduced, as opposed to AMP or SMP. AMP (Assymetric MultiProcessing) is quite suitable for real-time systems since a core does not communicate with another. However, it can be improved by allowing some limited communication. SMP (Symmetric MultiProcessing) is used in systems like Linux/Windows. It is not suited for real-time systems given the overhead that it requires to manage threads from one core to another. For example, the scheduler requires a spin lock (bad idea in real-time systems) to determine which thread to execute on which core. Additionally, if a thread migrates from one core to another, its stack has to be dumped from one L1 cache to another. This overhead, in the worst case (required to calculate the WCET) is extremely bad. In some cases (for example, CPUs without cache snooping), the WCET is so bad that it is probably just better to use one core than multi-core with SMP. So basically Pharos uses RMP design as a midway solution between AMP and SMP. RMP does not use spin locks nor is thread migration possible. RMP uses only wait-free algorithms (note that it does not even use lock-free algorithms) for inter-core communication. A core can communicate with another via a "heavy weigh queue" (2-copy messages) or via a "channel" (0-copy messages). Note that with a channel, a partition can send a message of up to 1 GiB (depends on the CPU) almost instantly, even from one core to another.

In Pharos, applications run in user mode (unless explicitly configured to run in supervisor mode) and cannot access the memory space outside its limits. An exception will be triggered by the hardware MMU/MPU if a partition tries to access a memory area to which it does not have permissions. Also, and very important in real-time critical systems, a thread must execute within configurable time limits.

Qualification

Qualifying/certifying a piece of software for safety critical systems is a somewhat overwhelming endeavor. A lot of tasks have to be performed, including tests, documentation, verifications, etc. Pharos is not qualified today to any standard. However it is our medium/long term goal to produce qualification artifacts that provide enough confidence that Pharos can be used in critical systems. Today, Pharos source code (you can check it yourself) was developed from the very beginning according to MISRA2004/2012, has a good number of comments, the cyclomatic number and nesting level are not high. Additionally, we also produced a (non open-source) test suite composed by mostly validation tests (although a few unit tests as well). The test suite (> 400 tests) is roughly 3x the size (>170 KLOCs) of the source code (which has ~59KLOCs). In addition we also keep an up-to-date user manual (open-source and you can download it freely from "Files" - https://sourceforge.net/projects/rtospharos/files/). We created also a high-level and low-level requirements documents (non open-source), however these are now outdated and need a revision to be kept on track for the new releases of Pharos. According to the standard that we could certify Pharos to, additional documentation/tests are needed. We are developing Pharos in our free-time, so we currently just don't have the resources to this. If you require certification and are willing to provide us with some resources, we are able to this job ;).

License

Pharos is available in open-source and under an Apache 2.0 license. Among other things, this means that you can freely use on your public/private domain projects as you wish, free of cost.

An overview

We designed Pharos to provide to support mixed-criticality applications. In essence:

  • applications are divided into partitions
  • each partition contains a set of threads
  • threads run in user mode
  • partitions cannot access the memory area of each other (unless configured to be able to do so)
  • each thread can be configured to have a maximum execution time

In other words, you could have an airbag and infotainment systems running under the same CPU and Pharos will guarantee that the low critical systems interference with the highly critical is under your applications defined limits. For example, the infotainment code will not be able to corrupt the memory area of the airbag. Furthermore, the infotainment could have high priority threads (to provide quick user response) and still Pharos can ensure that the lower priority but highly critical airbag threads will run, no matter what the high priority threads do. We refer this feature as "thread temporal execution monitoring".

Threads

Pharos divides the application into partitions, where each partition is composed by threads, semaphores, message queues, etc. Each partition threads can synchronize/communicate with each other using the standard OS features. Each thread can be:

  • periodic
  • sporadic
  • aperiodic

The periodic and sporadic threads have included a maximum time for each job to execute (should correspond to their WCET) and a deadline. If the thread attempts to take more time to execute, Pharos will notify the partition and stop the thread (and resume it when the period or the MIT as elapsed). If the thread deadline is reached, Pharos will call an error handler so that the application detects the fault.

While a periodic thread is easy to understand, a native support for a sporadic thread might be unknown to most users. Basically, a sporadic thread has the same properties as a periodic thread except instead of a period it has a MIT (minimum inter-arrival time). A sporadic thread can be activated at any time by a Pharos event, semaphore, message queue, etc. But the thread will be executed respecting its MIT: there must be a minimum time interval between two consecutive activations of the thread. This is similar to a periodic thread instead of a fixed period, there is a minimum "period".
The application defines which type of sporadic thread it wants, based on events, message queues, semaphores, etc. The entry point of the thread corresponds to a function that executes a job (hence there is no need for an infinite loop inside periodic or sporadic threads). The sporadic thread function will receive an argument corresponding to its type. For example, if it is activated by a message queue, it will get a message sent; if it is activated by an event, it will get the event sent and so on.

Aperiodic threads, by definition, do not have a maximum time (WCET) nor a deadline. However, since Pharos 2.0.0, aperiodic threads can also have a WCET and an associated "period" (AKA replenishment period) by which the application can limit its execution time. That is, each aperiodic thread has a budget that is replenished at each period. If the thread tries to execute more budget than configured (more time than it is supposed to), Pharos will stop the thread until the next period starts.

Using this method the lower priority threads can have a guarantee that the higher priority threads will relinquish the CPU and so they will have time to execute (as long as the application configured the maximum execution times of the higher priority threads appropriately).

Inter-partition communication/synchronization

A partition can also communicate and synchronize with other partitions through:

  • heavy weight message queue - data is copied from one partition to another (slow for big messages)
  • channel - data is sent from one partition to another simply by managing the MMU/MPU (very fast for big messages)
  • resource - used to ensure mutual exclusion. Uses internally a semaphore with priority ceiling algorithm and the calling thread can only execute the mutual exclusion code if it has enough time to fully complete it.
  • inter-partition calls - a partition can call directly (and safely) a specific function of another partition (with the exact prototype of the function). For example, "configure a UART to 155200 baud rate".
  • shared section - memory area that is accessible to all partitions
  • io memory - you can define specific memory areas where each partition has access to. For example, you can configure the same area to be accessed in read/write/whatever permissions for two partitions so they can share the region

One innovation that Pharos brings (to the best of our knowledge) is the introduction of filters for inter-partition objects. Inter-partition objects are not new themselves, but the way Pharos implements them and the way the application can use them is new (to the best of our knowledge). This mechanism is needed in multiple applications that have a resource (in the abstract sense of the word) that is used by multiple partitions but must be controlled. For example, a CAN driver can be used to transmit/receive messages from any partition. However, it should not be overloaded with messages from a faulty partition. Pharos introduces a filter function that is invoked before the message is transmitted (to the message queue or channel) or the resource accessed. It is run in the context of the calling thread but with memory permissions and stack of the partition being invoked. For example, suppose partitions A, B and C can send messages to a message queue of partition Z, but partition D cannot send messages to this queue. The code executed in filter for the message queue will have the same memory permissions as partition Z and will run with a stack in partition Z. However Pharos will still account for the time taken in executing the filter to the calling thread. This means that a faulty thread can only damage its own execution time and this will have no impact on partition Z (or any other partition). In this case, the filter code that will check if the message being sent is from partition D and if so, rejects it. The application is free to create more complex filters, such as limit the number of messages per second being sent, reject messages if the CAN queue is approaching its limits, etc.

Multicore - RMP

Multicore is supported in RMP (Real-time MultiProcessing) fashion on all the supported multicore CPUs (currently ARM Cortex-A53 and RISC-V). RMP fashion means that each core can be viewed as running its own separate Pharos but they can communicate between each other via channels or heavy weight queues. Partitions are allocated to one core, including its threads, semaphores, queues, etc.

The communication between cores is done via interrupts. That is, suppose core 0 wants to send an channel bulk to core 1. To do this, core 0 will trigger an interrupt on core 1. The algorithms involved are not only lock-free, they are also wait-free! This makes Pharos scalable across the number of cores. In theory (we did not test since we don't have the hardware), you could have a 1000 core system and the cores will only "talk" to each other as required by your application. No more, no less.
Thus the system is as scalable as your application allows it to be (i.e. if your application has each of the cores talking to the 999 other cores, then it might not be very efficient).

Supported hardware

The full list of currently supported CPUs is:

  • Arm
  • ARM926EJ-S (armv5)

    • VersatilePb board in qemu
  • Cortex-R5 (armv7-R)

    • Hercules TMS570LC43x LaunchPad Development Kit (http://www.ti.com/tool/LAUNCHXL2-570LC43) in lock-step (one core in redundancy). Sadly, our board has wear-down its flash (we believe) so we can no longer test in it. Currently we can only make sure that Pharos is compiled against it. If you desire support for this board let us know.
  • Cortex-M4 (armv7-M)

    • STM32F469I-DISCO (https://www.st.com/en/evaluation-tools/32f469idiscovery.html). This board from ST has a STM32F469NIH6 CPU, running at 180 MHz, 64 KiB CCM SRAM (extremely fast SRAM), 320 KiB SRAM, 4 KiB Backup SRAM, 128 Mbit SDRAM, 2 MiB Flash and more. This is the first port that Pharos is ported to that has more than one type of memory. Pharos has been extended in such a way that an application can easily select the memory type where it wants part (or all) of its memory. For example, you can place the stack of a thread on the fast CCM memory and a "large" global variable on the SDRAM, its up to you.
    • EK-TM4C129EXL (http://www.ti.com/tool/EK-TM4C129EXL)
    • Cortex-A53 (armv8-A)
    • Quad-core raspberry pi 3 in qemu
  • RISC-V

    • Quad-core RISC-V 64 bit Virt board in qemu (Sv39 MMU)

Hardware requirements

Pharos is designed to not take "too much" memory. We run it (with several threads/partitions/etc) on a 256 KiB SRAM board. Pharos itself needs about 20 KiB SRAM (depends on the CPU family). Although it requires some memory (more than other smaller RTOS), we believe it does required much. In compensation for the larger amount of memory, Pharos provides more functionalities, as stated earlier.

Where to start

Although you can navigate in the wiki pages, we suggest that we start with the User Manual. Follow the link https://sourceforge.net/projects/rtospharos/files/, select the folder with the latest version, and download the User Manual. There you have the latest information specific to the corresponding Pharos version. Have fun :)

Future work

The next release (3.5.0), apart from bug corrections, is focusing on adding a TCP/IP stack library, which is named RTN (Real-Time Networking).
We hope to release it soon (< 3 months).

Feedback

A quick questionnaire is in https://docs.google.com/forms/d/12-MQ6OuYhEM_1gX_nI-93eMPPB9tmTAg4hZ8BL_DQMI/viewform?edit_requested=true#responses please take 5/10 min to answer this. Your feedback will give us the direction for the way to go.

Support is available. Please make use of the Ticket system if you found a bug, use the Discussions to place questions or contact us at rtos.pharos@outlook.com.

Project Members:


Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.