Back to Writing
operating-systemssoftware-engineering

Writing Our Own Operating System (Part 3)

October 29, 2022

Read on Medium

Hello and welcome everyone to my third article in the series of articles that explains developing a simple minimal x86 Operating System step-by-step. As every article is a continuation of the previous articles it is recommended that you check out them before going through this article

As a quick recap, I set up the booting process for our OS and how to write code for our Operating System in C Language in the previous articles. Here are the links for those articles

In this article, I’ll try to explain how to display text on the console and how to write data to the serial port.

To display text on the console and how to write data to the serial port, we have to have drivers. Drivers are nothing but a piece of code that acts as a layer between the kernel and the hardware, providing a higher abstraction than communicating directly with the hardware. Let’s start our process by developing a drive for the frame buffer to display text on the console.

The Frame Buffer

The frame buffer is a piece of hardware that can display a memory buffer on the screen. The row and column indices in the frame buffer begin at 0, and there are 25 rows and 80 columns (so rows are labeled 0–24).

The frame buffer uses memory-mapped I/O then you can write to a specific memory address and the hardware will be updated with the new data. The starting address of the memory-mapped I/O for the frame buffer is 0x000B8000. The memory is divided into 16-bit cells, where the 16 bits determine both the character, the foreground color, and the background color.

Bit:     | 15 14 13 12 11 10 9 8 | 7 6 5 4 | 3 2 1 0 |
Content: | ASCII | FG | BG |

There are 16 colors available for us to use as foreground or background colors.I will use blue color on a gray background you can choose whatever color you like out of the below table

Available colors to use in a frame buffer

the following assembly code instruction is used to write the character A with a blue foreground (1) and a dark grey background (7) at position (0,0):

mov [0x000B8000], 0x4128

The above code is to be added to the loader.s file. alternatively, we can write to the frame buffer in C language by treating the address 0x000B8000 as a char pointer.

char *fb = (char *) 0x000B8000

and by using the below c function

https://medium.com/media/14536b2a4a9e7adb8edc10e663833122/href

if you call out the function from the kmain file and run the boot you will get an output like this

Output in blue foreground and light grey background

Moving the cursor

As for now, we have only able to print one character so to write the next characters we have to move the cursor to the next location on the buffer. The cursor of the frame buffer can be moved through two distinct I/O ports. So we have to use assembly code instructions such as in and out to communicate with the hardware

but we can’t directly execute the out assembly code instruction in C. So we wrap it in a function in assembly code which can be accessed from C through the cdecl calling standard.

create two files io.s and io.h (C header file)

https://medium.com/media/98a6bacc4154067b7203e00d73c84f9f/hrefhttps://medium.com/media/7e829a9fbb4757dddbe775fc59677d07/href

now we created two files but we also have to link them to the Makefile so we have to add one-word io.o next to kmain.o in Makefile

Finally we have to add the C function and then we can make run

https://medium.com/media/437ab57e5eb4748e32532f6e8cb1f91d/href

If we can we a BLINKING-LINE in the Bochs emulator we are good to go.

The Driver

The driver should provide an interface that the rest of the code in the OS will use for interacting with the frame buffer. We can write our own C function for this. Below code shows such sample function

https://medium.com/media/0cea50f0edc9a3d4805c4588e9d9b57e/href

We can enter whatever we like and that will be displayed on the console

The Serial Ports

Now let’s look at how to develop and create a driver for the serial port. the serial port is nothing but an interface for communicating between hardware devices. If a computer has support for a serial port, then it usually has support for multiple serial ports, but we are only making use of one of the ports. This is because we will only be using the serial ports for logging and only for output. After that Bochs can save the output from the serial port in a file, effectively creating a logging mechanism for the operating system.

Create two files (serial.h and serial.c)to develop code for drivers for the serial ports Use the following code and read the comments for more details about each configuration.

https://medium.com/media/3cfc9aaf9c8651c193e38300b466ccb5/hrefhttps://medium.com/media/faeee5bb32232385b5f92d6ec40524d4/href

Writing the data to the Serial Port

Writing data to the serial port is done through the data I/O port. But before writing, we have to make sure, the transmit FIFO queue is empty (all previous writes must have finished). The transmit FIFO queue is empty if bit 5 of the line status I/O port is equal to one. If you scroll back up and check the serial.c and serial.h files, you’ll see I have already added a function to check this. Writing to a serial port means spinning as long as the transmit FIFO queue isn’t empty, and then writing the data to the data I/O port.

Reading the contents of an I/O port is done via the in assembly code instruction. We have to do the same way as theout assembly code we did earlier.

https://medium.com/media/0bd15124d2db7bde85cad738542bc6d3/href

we have to also make changes in header file

https://medium.com/media/6f90e817642965165f56726eeded3145/href

Configuring Bochs

The Bochs configuration file bochsrc.txt must be modified to save the output from the serial port. The com1 configuration instructs Bochs on how to handle the first serial port. Add this to the bochsrc.txt file.

com1: enabled=1, mode=file, dev=com1.out

The output from serial port one will now be stored in the file com1.out.

The Driver

Now let’s implement a write function for the serial port similar to the write function in the driver for the frame buffer.

https://medium.com/media/a6100994e461c2c397515df81d363b39/href

with this we come to the end of our article .you can try to implement a printf-like function. Hope you have found this easier to follow and created your first drivers . you can find the code to in the following repository

GitHub - Birunthaban/OperataOS

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

Writing Our Own Operating System (Part 3) — Birunthaban Sarventhiran