x86 supports two virtual memory schemes (read about it here):
- segmentation, must, managed using the segment table, GDT.
- paging, optional, managed using the page table, PDT.
Most operating systems want to to use paging and don't want the segmentation, but its must and can't just be disabled.
So the trick is to disable its effect as it wasn't there. This can usually be done by creating 4 large overlapped segments descriptors (beside the null segment):
- segment index 0 : null segment descriptor
- segment index 1 : code segment descriptor for the privileged (kernel) mode
- segment index 2 : data segment descriptor for the privileged (kernel) mode
- segment index 3 : code segment descriptor for the non-privileged (user) mode
- segment index 4 : data segment descriptor for the non-privileged (user) mode
all these segments starts from 0x00000000
up to 0xffffffff
, so you end up with overlapped large segments that is privileged code and data, and non-privileged code and data in the same time. This should open up the virtual memory and disable the segmentation effect.
The processor uses the segment selectors (segment registers cs
, ds
, ss
...) to find out the right segment (once again, the segmentation is must).
Every segment selector is 16 bit size and has the following layout (source):
The first two bits indicates that privilege level, x86 supports 4 levels, but only two of them actually used (00
highest, and 11
lowest).
The third bit indicates the table should be used, mostly 0
, the GDT.
- The rest 13 bits indicates the segment index.
If you interpreted the 0x08
that is loaded in cs
, it will be in binary:
0000000000001 0 00
index 1 (code) GDT privileged
and the 0x10
that is loaded in ds
, ss
, ... :
0000000000010 0 00
index 2 (data) GDT privileged
If you read the segment selectors of any user mode program you should see that the cs
value is 27
(0x1b
) which means:
0000000000011 0 11
index 3 (code) GDT non-privileged
and the data selectors ds
, ss
, ..., should store 35 (0x23
):
0000000000100 0 11
index 4 (data) GDT non-privileged
The data segments selectors (registers), can be easily modified using simple mov
instruction, but the cs
can't be used with mov
, so you use jmp 0x08:OFFSET
to load the segment configurations into the the code segment selector.