Let’s make your own operating system (#week 4_Segmentation)

Nimantha Gayan
3 min readAug 13, 2021

This is the fourth article in this series. In this article, I will discuss how to integrate segmentation. In the past article, I disclosed how to how to integrate outputs and you can look at it by clicking here.

Segmentation

Segmentation in x86 means accessing the memory through segments. Segments are portions of the address space, possibly overlapping, specified by a base address and a limit. To address a byte in segmented memory you use a 48-bit logical address: 16 bits that specifies the segment and 32-bits that specifies what offset within that segment you want. The offset is added to the base address of the segment, and the resulting linear address is checked against the segment’s limit — see the figure below. If everything works out fine (including access-rights checks ignored for now) the result is a linear address. When paging is disabled, then the linear address space is mapped 1:1 onto the physical address space, and the physical memory can be accessed.

Accessing Memory

The processor has six 16-bit segment registers. Which are cs, ss, ds, es, gs and fs. The register cs is the code segment register and specifies the segment to use when fetching instructions. The register ss is used whenever accessing the stack and ds is used for other data accesses. The OS is free to use the registers es, gs and fs.

So, here’s the assembly code for the file called “gdt.s” which is located in a newly created directory called “segmentation”. This will help to access the memory

The Global Descriptor Table (GDT)

A GDT/LDT is an array of 8-byte segment descriptors. The first descriptor in the GDT is always a null descriptor and can never be used to access memory. At least two segment descriptors (plus the null descriptor) are needed for the GDT, because the descriptor contains more information than just the base and limit fields. The two most relevant fields for us are the Type field and the Descriptor Privilege Level (DPL) field.

The DPL specifies the privilege levels required to use the segment. x86 allows for four privilege levels (PL), 0 to 3, where PL0 is the most privileged. In most operating systems , only PL0 and PL3 are used. However, some operating system, such as MINIX, make use of all levels. The kernel should be able to do anything, therefore it uses segments with DPL set to 0 (also called kernel mode). The current privilege level (CPL) is determined by the segment selector in cs.

The segment descriptors needed.

Note that the segments overlap — they both encompass the entire linear address space. In our minimal setup we’ll only use segmentation to get privilege levels.

Loading the GDT

Loading the GDT into the processor is done with the “lgdt” assembly code instruction, which takes the address of a struct that specifies the start and size of the GDT. To do that you need to declare functions and structures within a file called “segments.h” which is in the “segmentation” directory.

Then we need to define those functions in a file called “segments.c” which is also in the “segmentation” directory.

finally open the terminal and run the “make run” command and then run the bochs emulator. if you done successfully run the emulator without error.

Thank you…

--

--

Nimantha Gayan

Software Engineering Undergraduate, University Of Kelaniya