Tyros Operating System: design and architecture overview

An Introduction to the Tyros Operating System

Tyros is an operating system based on the Neutronix microkernel. What does term 'microkernel' mean? It means that only a small part of the system works in a supervisor mode (ring 0 on an x86). This part of the system is called a microkernel. All other services usually found in classic operating systems (such as filesystem, networking etc) are implemented as standalone user-space processes, and they are called servers. Thus, a microkernel-based operating system is a combination of the microkernel and various servers.

Why yet another operating system?

Classic operating system architectures (both monolithic and microkernel ones) are not flexible enough. It is almost impossible for a monolithic system designer to move some services from kernel to user mode. And generally it is not easy to implement some of the functionality of microkernel servers in the microkernel itself.

There is only one way to solve this problem: neutrality. The kernel of a flexible operating system should not be "too monolithic" or "too micro". It can have any architecture "de jure", but developer should not decide himself what to implement as a part of the kernel and what to load as a user process. This should be user's choice

Thus, our primary goal is to make the kernel architecture flexible enough to allow it to load the same service as a part of the kernel (and have all advantages of the monolithic design) or as a standalone user server (and have all advantages of the microkernel design)

In ideal, the same service should have three different ways of working:

And there should not be need of having three different variant of the service to accomplish this goal ;)

What has been already done?

Currently (Jun 27, 2003) we have the working microkernel with basic functionality implemented (multitasking, multithreading, virtual memory management, signals and messages - everything it needs except synchronization primitives) which is capable of running on IA-32 (x86) computers with 8+ Mb RAM.

Tyros Operating System Architecture

Logical Structure

Tyros is logically divided into three parts:

Loading and Initialization

The first program that receives control after the bootloader had switched into protected mode is called Tyros Kernel Loader. Its task is to create kernel image in memory thus making it capable of executing (the kernel is in ELF format). After this the control is passed to HAL entry point (hal_entry() func). Then hal_main() is called which initializes internal kernel facilities:

Then core_entry() is executed which starts up some critical servers (such as nameserver and debugging console)

Threads and Processes

In fact, there is only one unit of execution in Neutronix: a process. But different processes can have the same address space (thus being different threads of a process). Term 'thread' is only used when we need to distinguish processes with different address spaces from processes with the same address space. When this difference doesn't matter, the term 'process' is used.

The terms 'process' and 'task' are the same, but the first one is generally used when referring to a process in CORE and the second one is used when referring to a process in HAL

Though, each process is identified by its TID (task identifier - that's because this identifier is the same for the HAL and for the CORE)

Interprocess communication

Primary IPC primitives of the Neutronix are messages. Each process receives its mailbox at startup which can be used to receive messages. Messages can only be send from one process to another (no ports etc) and the receiver is identified by TID.

There are three system calls which are used for sending and receiving messages. They are:

The combination of wait and recv is generally used to receive a message in synchronous mode

A message is a message_t structure which consists of:

The Neutronix microkernel gives no special meaning to the contents of the message - this meaning is only defined by the sender and the receiver

Interrupts handling

User-space process can install its own interrupt handler (given it has enough privelege). This is accomplished through attach system call. The only type of attaching supported at present is AT_REALTIME - that means that control will be immediately passed to attached handler AND interrupts will be disabled during its execution (I know this is a major stability problem, but...)

Uninstalling of interrupt handler is done using detach system call

Virtual Address Space

Each process is granted its own virtual address space. Its system area is first 2 gigabytes (0x00000000 - 0x7FFFFFFF) and its user area is high two gigabytes (0x80000000 - 0xFFFFFFFF). System areas of all processes are the same and usually user processes have no access to system area (it becomes possible on a ring3->ring0 switch, which occurs during system call)

High (user) memory areas are different between processes thus guaranting memory protection

System Memory Requests

The only way for a process to receive access to the system memory area is a system memory request. A process, given it has enough privelege, can request a part of system memory area to be mapped into his user virtual address space. This is accomplished through req_sys_mem system call

Security System

The Neutronix microkernel supports a simple, but very efficient way of protection. Each process is given its privelege level which may be 0 (supervisor) or non-zero (user). Only supervisors are capable of installing theirs interrupt handlers or requesting system memory and only supervisors can spawn other supervisors. Process' privelege level may be equal or less than its parent's and each thread is given privelege level of its parent.

Such a simple security system allows to implement much more complex systems using only servers and not touching the microkernel itself

Last updated: Jun 27, 2003

© 2003 Andrew 'Lonesome' Ptitsyn <lonesome AT users DOT sourceforge.net>