Create Your Own Operating System

Malshani Dahanayaka
5 min readAug 27, 2021

--

PART 06 — Integrate user-modes

This is the 6th week in a row of the “Build Your Own OS” series. I hope you have studied my last articles in this series. If you missed them, please study those articles.

There are two modes of operation in the operating system to make sure it works correctly. These are user mode and kernel mode.

The processor switches between the two modes depending on what type of code is running on the processor. Applications run in user mode, and core operating system components run in kernel mode. While many drivers run in kernel mode, some drivers may run in user mode.

User Mode

When the operating system is running a user application such as handling a text editor, the system is in user mode. The transition from user mode to kernel mode occurs when the application requests the help of the operating system or an interrupt or a system call occurs.

In the user mode, the mode bit is set to 1. It is changed from 1 to 0 when switching from user mode to kernel mode.

Kernel Mode

The system starts in kernel mode when it boots and after the operating system is loaded, it executes applications in user mode. There are some privileged instructions that can only be executed in kernel mode. These are interrupted instructions, input-output management, etc.

In the kernel mode, the mode bit is set to 0. It is changed from 0 to 1 when switching from kernel mode to user mode. All code that runs in kernel mode shares a single virtual address space. This means that a kernel-mode driver is not isolated from other drivers and the operating system itself. If a kernel-mode driver accidentally writes to the wrong virtual address, data that belongs to the operating system or another driver could be compromised. If a kernel-mode driver crashes, the entire operating system crashes.

The transition from user mode to kernel mode and back again.

Loading an External Program

Somehow we need to load the code we want to execute into memory. So, where do we get the external program from? Usually, more feature-complete operating systems have drivers and file systems that enable them to load the software from a CD-ROM drive, a hard disk, or other persistent media.

Here, we will use a feature in GRUB called modules to load the program, instead of creating all these drivers and file systems.

GRUB Modules

GRUB can load arbitrary files into memory from the ISO image, and these files are usually referred to as modules. To make GRUB load a module, edit the file iso/boot/grub/menu.lst and add the following line at the end of the file:

module /modules/program

Now create the folder iso/modules:

mkdir -p iso/modules

To instruct GRUB how to load our modules, the “multiboot header” — the first bytes of the kernel — must be updated as follows:

GRUB will also store a pointer to a struct in the register ebx that, among other things, describes at which addresses the modules are loaded. Therefore, you probably want to push ebx on the stack before calling kmain to make it an argument for kmain.

Aslo we need to modify the kmain.c file to get arguments.

Create a Simple programe and Compile It.

In this article we make a simple programe to perform only few actions.Therefore, a very short program that writes a value to a register suffices as a test program.

Compiling

Since our kernel cannot parse advanced executable formats we need to compile the code into a flat binary. NASM can do this with the flag -f:

nasm -f bin program.s -o program

You must now move the file program to the folder iso/modules.

Executing the program with C

before to leaping to the program we should discover where it stores in memory . Expecting that the contents of ebx is passed as an argument to kmain , we can do this totally from C .

The pointer passed to kmain in the ebx register can be cast to a multiboot_info_t pointer. The address of the first module is in the field mods_addr. The following code shows an example:

However, before just blindly following the pointer, you should check that the module got loaded correctly by GRUB. This can be done by checking the flags field of the multiboot_info_t structure. You should also check the field mods_count to make sure it is exactly 1.

jump to the code loaded by GRUB and it is simpler to parse the multiboot structure in C than assembly code, calling the code from C is more convenient (it can of course be finished with jmp or call in assembly code too).

kmain function:

also you need to save the multiboot.h file with your kernel files.

This is the source code in the file multiboot.h.

After the this week implementation you can open terminal and type command

make run

Now you can see On the screen, Bochs will indicate that grub has loaded a module.

if we see 0xDEADBEEF in the register eax via the Bochs log, We have successfully started a program in our OS!

Hope you all get a good idea about how to easily execute a small program in kernel mode. See you in the next article.

Reference: Helin, E., & Renberg, A. (2015). The little book about OS development

Thank You For Reading………..

— Malshani dahanayaka —

--

--

Malshani Dahanayaka

Software Engineering Undergraduate of University of Kelaniya