Implementation of SachOS (Part 04)

Sachithra_Manamperi
3 min readAug 13, 2021

This is the fourth article in the series.
In this blog, I’ll discuss how to integrate segmentation.
I covered how to integrate outputs in a previous article, which you can read by clicking here.

I’m following Erik Helin and Adam Renberg’s guide “The Little Book About OS Development” for those coding and implementation employees.

In x86, segmentation refers to the use of segments to access memory. Segments are overlapping parts of the address space defined by a base address and a limit. In segmented memory, you should use a 48-bit logical address to address a byte: 16 bits for the segment and 32 bits for the offset you desire within that segment.

The offset is added to the segment’s base address, and the resulting linear address is compared to the segment’s limit, as shown in the diagram below. If everything goes well, you’ll get a linear address. When paging is disabled, the linear address space is mapped 1:1 to the physical address space, allowing access to the physical memory.

Conversion of Logical addresses to linear addresses.
To allow segmentation, you’ll need to create a segment descriptor table, which is a table that describes each segment. The Global Descriptor Table (GDT) and Local Descriptor Tables (LDT) are the two types of descriptor tables in x86 (LDT).
User-space processes create and manage LDTs, and each process has its own LDT. If a more complex segmentation model is desired, LDTs can be used; however, we will not do so.

Getting into the memory access

When accessing memory, most of the time there is no need to specify the segment to use directly. Six 16-bit segment registers are available on the processor. These are the letters cs, ss, ds, es, gs, and fs. The code segment register (cs) defines which segment should be used for fetching instructions.
When accessing the stack, the register ss is utilized, and when accessing other data, the register ds is used. The OS is free to use the es, gs, and fs registers.
So, here’s the assembly code for the file “gdt.s” in the “segmentation” directory, which was recently generated. This will assist with memory access.

The Global Descriptor Table (GDT)
A GDT is an 8-byte segment descriptor array. The GDT’s initial descriptor is always null, and it can never be used to access memory. Because the descriptor carries more information than only the base and limit fields, the GDT requires at least two segment descriptors. The Type field and the Descriptor Privilege Level (DPL) field are the two most important fields for us.

Loading the GDT

The “lgdt” assembly code instruction loads the GDT into the processor by taking the address of a struct that specifies the GDT’s start and size. To do so, create a file called “segments.h” in the “segmentation” directory that declares functions and structures.

Then, in a file called “segments.c” in the “segmentation” directory, you must define those functions.

To execute your OS, you must now configure the “Makefile” as follows.

then make the following changes to the kmain.c file:

The “segments install gdt” function in the “kmain.c” file can now be called. If your OS booted without issues using the “make run” command after you completed those steps, segmentation was successfully incorporated. I believe you have a decent understanding of how to integrate segmentation. This link will take you to my Github repository.
Thank you for reading, and I’ll see you next week for part 5 of this series.

--

--

Sachithra_Manamperi

Undergraduate | Software Engineering | Dharmaraja College Kandy | Sri Lankan