Build Your Own OS #4

Segmentation Process

When a program is loaded into memory, the segmentation system tries to locate space that is large enough to hold the first segment of the process, space information is obtained from the free list maintained by memory manager. Then it tries to locate space for other segments. Once adequate space is located for all the segments, it loads them into their respective areas.

Segmentation in x86

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. A 48-bit logical address is used to address a byte in segmented memory: The segment is specified by 16 bits, while the offset inside that segment is specified by 32 bits. 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.

Accessing Memory

When accessing memory, most of the time there is no need to specify the segment to use directly. cs, ss, ds, es, gs, and fs are the six 16-bit segment registers on the processor. The code segment register (cs) defines which segment should be used for fetching instructions. When accessing the stack (through the stack pointer esp), the register ss is used, while ds is used for other data access.

func:
mov eax, [esp+4]
mov ebx, [eax]
add ebx, 8
mov [eax], ebx
ret
func:
mov eax, [ss:esp+4]
mov ebx, [ds:eax]
add ebx, 8
mov [ds:eax], ebx
ret

The Global Descriptor Table (GDT)

A GDT/LDT is an eight-byte segment descriptor array. The GDT’s initial descriptor is always null, and it 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.

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.

struct gdt {
unsigned int address;
unsigned short size;
} __attribute__((packed));
lgdt [eax]
Bit:     | 15                                3 | 2  | 1 0 |
Content: | offset (index) | ti | rpl |
mov ds, 0x10
mov ss, 0x10
mov es, 0x10
.
.
.
; code here uses the previous cs
jmp 0x08:flush_cs ; specify cs when jumping to flush_cs flush_cs:
; now we've changed cs to 0x08

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store