Operating Systems, Programs
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.
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.
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.
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.
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
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.
Then we can load the OS wait a few minutes and check the Bochs log to verify if our program has run correctly.
Helin E, Renberg A. (2015). The little book about OS development: https://littleosbook.github.io/
Os Dev Wiki https://wiki.osdev.org/Main_Page
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.