Far jump in gdt in bootloader

assembly, bootloader, gdt, x86

Solution

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.

Problem

``` flush_gdt: lgdt [gdtr] jmp 0x08:complete_flush complete_flush: mov ax, 0x10 mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax ret ``` I am unable to understand what this code does . `flush_gdt` is a label okay , then `lgdt [gdtr]` loads the `48-bit` pointer in `gdtr` register and after that from `jmp 0x08:complet_flush` . What does jmp instruction do ? and then why are we moving 0x10 to ax and then subsequently to other registers

Original source