49 is an operating system that takes multiples ideas from
kernels like L4 and operatings systems like Plan9 and
OpenBSD. It is meant to be an operating system with a fixed
size, meaning that it never allocates memory for itself
and its size at boot time remains constant. The size of the
kernel can be changed by a user through configuration to
match its platform.
This has the benefit of making allocation simply for user
space. There is also no virtual page tables CR3 operations
besides the kernel one to map all memory. The memory is 1
to 1 mapped to allow usage of the MPU.
Communication among tasks is done through shared buffers
called seats. When the kernel boots, it takes a set amount
of seats represented by a fixed size array. These seats are
all of PAGE_SIZE and can be either vacant or occupied. When
a task wants to communicate with another it takes a seat
and waits before exchanging information.
Fragmentation is solved by moving chunks of innactive
threads. The chunks are all of PAGE_SIZE.
Userspace programs request memory in a different way. When
compiling a program you specify how much fake dynamic
memory (FDM) the program needs. The fake memory is added at
runtime. Hence, memory allocation is based on that memory
chunk and not a syscall to request pages from the kernel.
This will force you to tell how much RAM your program
really needs instead of pretending to be lightweight. Hence,
when a program does a `malloc` it takes a seat with the
allocation server which reads the FDM and returns either the
part needed or and error to say that there is no memory left.
The layout of the operating system image is :
[ boot ] [ identifier ] [ boot 2 ] [ kernel ] [ alpha ] ...
The identifier is a magic number combined with a date and
time to identify the PCI device used by the boot drive. The
date and time is passed to the bootloader at compile time.
The second stage bootloader reads the driver part of it and
loads it into memory then passes the ident to the kernel.
The kernel then passes it to the root task which starts the
PCI server to search for that specific device with the
ident. Afterwards it starts the driver server and the
filesystem server to load the remaining needed drivers. This
makes it so only required drivers are loaded. When the OS
is installed on a storage device, the image just changes the
storage type byte in the ident sector.
Each programs in its executable header mentions the resources
it will use. Programs also can have communication channels
which ask to reserve seats. Seats are all simplex. There is
no half-duplex or duplex. Half-duplex and duplex are implemented
at the userspace level with the reaction of the receiver from
the sender. The kernel only job is to read seats every timer
interrupt and wake up the receiver when data is available or
ignore the packet if there are no receiver. Example of 2 threads
Seat A Seat B
[ ThreadA => Thread B ] [ ThreadB => ThreadA ]
The behaviour of simplex/duplex/half-duplex is handled by the
thread through communication. The kernel only job is to wake
threads. I call this the seat protocol.
The Root Task (alpha) goal is to strip away the header and load
executable in memory. Essentialy the root task is the loader.
Features:
- Buggy
- Unsafe
- Incomplete
- POSIX unfriendly
- No ELF
- and more