Operating Systems, Programs

Mahela Dissanayake
4 min readAug 27, 2021

Hello everyone, In today’s article I’m going to talk about how to configure your operating system to run a user program. Up to this point, all we did was directly changing the kernel code. After this, we’ll be able to separately code a program and run it in our operating system.

User mode and Kernel mode

The User mode is normal mode where the process has limited access. While the Kernel mode is the privileged mode where the process has unrestricted access to system resources like hardware, memory, etc. A process can access I/O Hardware registers to program it, can execute OS kernel code and access kernel data in Kernel mode. Anything related to Process management, IO hardware management, and Memory management requires the process to execute in Kernel mode.

A process in Kernel mode get power to access any device and memory, and at the same time any crash in kernel mode brings down the whole system. But any crash in user mode brings down the faulty process only. The kernel provides System Call Interface (SCI), which are the entry points for the kernel.System Calls are the only way through which a process can go into kernel mode from user mode. To support kernel mode and user mode, the processor must have hardware support for different privilege modes.

My Experience

The GRUB bootloader we used for the OS has the ability to load external programs called modules from the iso into memory. To do this first we have to add the following line into the menu.lst file and create a path for the modules.

module /modules/program

After this, the code that is used to call the kmain should be updated to pass the information about the modules to it. It is also necessary to align all the loaded modules on the page boundaries when loading them. In order to do this the first byte of the kernel called “Multiboot header” needs to be configured.

Configuring the loader file

Now we’ll need to make a simple program to load into our OS. So a program that can write a value to the registers is enough for this step. You’ll notice that this program is very similar to the “HELLO CAFEBABE” code we did at the start. The only major difference is previously we wrote the value to the register directly from the kernel but this time we are writing a separate program to do this.

A simple program to change the registers

After writing this code save it in a .s file and use NASM to convert it into flat binary since our kernel can’t handle advanced executable formats.

This code will trigger an infinite loop so after Bochs is run we can halt it and look at the bochs log to verify if the code worked.

After the module is loaded we need to find it in the memory before we can run it. Since we passed the contents of the ebx register we can do this completely from C.

The ebx points to a special multiboot structure. You can download the multiboot.h file from http://www.gnu.org/software/grub/manual/multiboot/html_node/multiboot_002eh.html to utilize this.

Then the pointer in the ebx register can then be passed into a multiboot_info_t pointer.

C code to pass the pointer

After the values are passed into the pointer we’ll need to check if the module is loaded correctly, and that only one module is loaded. After we verify it then we can call our program.

Code to verify and run the program

Then we can load the OS wait a few minutes and check the Bochs log to verify if our program has run correctly.

The bochs interface after loading the modules
EAX register value is changed in the bochslog.txt
The output in Com.out file

References

Helin E, Renberg A. (2015). The little book about OS development: https://littleosbook.github.io/

Os Dev Wiki https://wiki.osdev.org/Main_Page

linux-insides https://0xax.gitbooks.io/linux-insides/content/

GNU GRUB Multiboot Manual http://www.gnu.org/software/grub/manual/multiboot/

Thank you for reading and I will be back next week with the next article.

--

--

Mahela Dissanayake

Software Engineering Undergraduate of University of Kelaniya, Sri Lanka.