Default SWEB’s features
The following tutorial provides a short overview of the course relevant components of SWEB. The reader is required to have already a basic knowledge about key operating system concepts like threads, memory management paging, system calls, …
Whenever mentioning SWEB in this document it refers to the basic SWEB delivered to you at the beginning of the operating systems course.
The basic SWEB that is accessible for you comes with the following features:
Support for arbitrary number of threads
Paging / basic Memory management
text print to screen
A file system implementation
Feel free to implement new exciting features like a mouse driver, graphic support, network card-driver and many more, during the term
The technique of SWEB
This section explains you theoretically how SWEB is compiled, stored, booted and executed.
SWEB’s kernel is compiled by using the
g++1). The file is nothing than a default binary program. Of course there are some restrictions:
The kernel can not make use of any libraries and functions, like those provided by the libc2). The reason for that is simple. All libc calls are system calls themselves or the functions make use of system calls. Those system calls require a running operating system to handle them. Therefore when writing an operating system you have to start with nothing!
Moreover, the kernel is not allowed to throw exceptions since there won’t be a runtime environment catching them.
Virtual disk image and booting
SWEB is stored on a virtual disk image. This is a special file on the hard disk of your computer. The format of the file is equally the same as for a real hard disk. SWEB’s image is split up into four partitions and at it’s beginning the boot signature and a small modified version of GRUB3) are located.
The first partition contains the compiled kernel of SWEB and the second the user programs. If you boot SWEB from the virtual machine of your choice first GRUB is invoked. Then GRUB loads the kernel into memory and calls the boot.s from the kernel. This will set up paging and finally call a function called
startup() from the
startup() was called, SWEB is considered to be running.
Startup() will perform some setups. First, it determines the amount of available Kernel Memory, followed by the creation of the Kernel Memory Manager and the Page Manager. The functionality of the most important of the mentioned components is described in detail in the following section.
Then the console is created. As you know for sure it is used to print text to the screen. The next step is the initialization of the Virtual File System.
Scheduler is created and started.
Some part of an operating system always depends on the used computer (CPU) architecture. Interrupt and execution-threads handling is platform specific to a large degree. Therefore SWEB has two separate classes called
Arch stands for “architecture“) for dealing with this issue. In the following step, these two classes are set up.
Now that everything necessary for managing and handling is created, the kernel services can start to run and the user programs can be loaded. The already created console is added to the scheduler’s list of executed threads. The second kernel thread started in the startup sequence is the “ProcessRegistry” thread. It mounts the second partition of the virtual disk image containing the user programs and starts them up as defined in
As a final step in the startup, the Scheduler’s
yield() method is called, resulting in a context switch.
The course tasks relevant SWEB components and classes are explained here in short:
Operating system services are implemented as kernel threads. Examples are the console, the idle thread, and the ProcessRegistry (for details see above). Kernel threads have (theoretically) full access to all kernel resources. To create a kernel thread you just have to derive from the Thread base class and implement the run method.
In basic SWEB, a user program is a special kind of thread, that runs the code provided in a binary file. SWEB uses the
ELF325) format for user programs. These programs are created by writing C code and compiling it with a compiler that is able to create
ELF32binaries, like the
GCC6) and linking SWEB’s libc to it.
Feel free to try to run your SWEB binaries on a Linux operating system and vice-versa and see what happens!
The Scheduler is the manager of the threads. Every time a timer interrupt happens or a thread voluntarily calls the Scheduler’s yield method, the schedule method is invoked. It will pick the next waiting runnable thread from the list and set it as the active thread. Note that there will always be at least one ready thread, namely the idle thread.
As you might already know, SWEB uses a very common memory management technique called paging. Therefore the memory is split up into a number of pages with a fixed page size (usually a power of 2). The Page Manager is the allocation unit for physical pages. It keeps track of used and free pages. If a thread needs another piece of memory for its code or data it has to request a page at the Page Manager.
If a CPU interrupt is triggered, some code to handle it is necessary. The implementation of
x86 interrupt handling can be found in the file “arch/x86/source/InterruptUtils.cpp”.
On x86 there are basically two types of interrupts. First, there are errors caused while execution like divide by zero exceptions, page faults, invalid op-codes, and many, many more. Second, there are so-called interrupt requests – short IRQ – caused by software (operating system) or by hardware (a device: keyboard, disk, network card, …).
Let’s look briefly at the most important IRQ handlers:
The timer-interrupt is caused by a timer overflow. The handler (irqHandler\_0) invokes the Scheduler’s
schedule() method, which picks a new thread from the list to run.
Page Fault Handler
A page fault occurs if a thread tries to access a virtual memory location that cannot be resolved to a valid physical memory address. A page fault does not automatically mean a serious error. In most cases, the problem can be handled and the fault-causing program can continue to run as normal. There are multiple reasons causing a page fault.
If a user program tries to access a memory region out of its range (e.g. because of a pointer error as null-pointer dereferences) a page fault is triggered and the program will be killed because of a segmentation fault. This also prevents user programs from accessing the kernel area!
Other reasons for page faults are implementation-specific reasons. For instance, virtual memory tries to expand the available memory by using the disk. If the memory fills up it starts to swap out (=write out) pages to the disk (swap device) and freeing them in memory. If a page is swapped out its mapping is kept valid, but the present flag in the page-table entry will be cleared. If a program tries to access a swapped page it will cause a page fault. The page fault handler has to swap that page back in and the program can continue.
Another example of a page fault is explained here. A binary user program is loaded on demand in SWEB. This means when a new user thread running a program is created the execution code contained in the binary file will not be loaded at all. At creation, only the headers of the
ELF32 file are read out and the thread’s CPU registers – like the
EIP (=instruction pointer) – will be set. When the thread starts to run it will try to reference the memory location pointed to by the instruction pointer. Since this memory location is not in memory it will cause a page fault.
This is where the Loader comes in. Each process has an instance of a class called the Loader. The Loader manages the address space of the thread. The Loader class provides a method for loading one code page from the binary file into the memory (
Kernel Memory Manager
Handles the kernel space memory and provides a malloc/free implementation (and the overloaded-operators
delete) for kernel services. Note that this implementation is not available for user-space programs!
5) ELF32 – Executable and Linkable Format 32bit – http://en.wikipedia.org/wiki/ELF32