From Grub to protected mode (1)

This is part of the project but not in its final presentation, those are just some notes on how to progress from Grub to protected mode.

First of all we need to have a bootable floppy image with Grub installed, then have our kernel copied inside. Our kernel must be Multiboot conformant. I’ve chosen to use an ELF with the Multiboot info inside, we will be seeing how to produce such a binary. First of all the Multiboot header must be contained in the executable, the structure of the Multiboot header is the following:

Offset Type Field Name Note
0 u32 magic required
4 u32 flags required
8 u32 checksum required
12 u32 header_addr if flags[16] is set
16 u32 load_addr if flags[16] is set
20 u32 load_end_addr if flags[16] is set
24 u32 bss_end_addr if flags[16] is set
28 u32 entry_addr if flags[16] is set
32 u32 mode_type if flags[2] is set
36 u32 width if flags[2] is set
40 u32 height if flags[2] is set
44 u32 depth if flags[2] is set

As we will be producing an ELF image the address information does not need to be contained in the Multiboot header, thus bit 16 won’t be set. In this first example we will not need to provide the video information, as the text mode is OK for now, so the bit 2 will be set to 0.

The idea to have an OS image loaded with Grub is the following: when the computer boots Grub is the default bootloader and then the user is prompted to choose which boot image wants to load. Our ELF will be selected, from this moment our binary OS image is running.

The state of the machine after Grub has just jumped to the entry point of our image is the following ( the info was extracted using Bochs):

eax:0x2badb002
ebx:0x2ca20
ecx:0x1f600
edx:0x0
ebp:0x67ee4
esi:0x2cb3f
edi:0x2cb40
esp:0x67ed4
eflags:0x46
eip:0x110098
cs:s=0x8, dl=0xffff, dh=0xcf9a00, valid=1
ss:s=0x10, dl=0xffff, dh=0xcf9300, valid=7
ds:s=0x10, dl=0xffff, dh=0xcf9300, valid=7
es:s=0x10, dl=0xffff, dh=0xcf9300, valid=1
fs:s=0x10, dl=0xffff, dh=0xcf9300, valid=1
gs:s=0x10, dl=0xffff, dh=0xcf9300, valid=1
ldtr:s=0x0, dl=0x0, dh=0x0, valid=0
tr:s=0x0, dl=0x0, dh=0x0, valid=0
gdtr:base=0x8f5c, limit=0x27
idtr:base=0x0, limit=0x3ff
dr0:0x0
dr1:0x0
dr2:0x0
dr3:0x0
dr6:0xffff0ff0
dr7:0x400
tr3:0x0
tr4:0x0
tr5:0x0
tr6:0x0
tr7:0x0
cr0:0x60000011
cr1:0x0
cr2:0x0
cr3:0x0
cr4:0x0
inhibit_mask:0
done

If we analyze a little bit this information we can get the following conclusions:

  • cr0:0×60000011:
    • bit 0 == 1: PE Protection Enables. We are in protected mode.
    • bit 31 ==0: PG Paging. Paging is disabled.
  • GDTR: We will have a look at the descriptor table.
    Null Segment Descriptor (SR=0):
    0×00008f5c : 0×00000000
    0×00008f60 : 0×00000000

    Code Segment Descriptor (SR=0×08)
    0×00008f64 : 0×0000ffff
    0×00008f68 : 0×00cf9a00

    The rest of the segments (SR = 0×10):
    0×00008f6c : 0×0000ffff
    0×00008f70 : 0×00cf9300

From the previous information we can extract that after the beginning of the execution of our code the processor has the A20 gate enabled, the processor is running in protected mode without paging enabled and that all the segment are 4Gb of size, we can access in a lineal way to all our memory.

In the following post I’ll explain how to progress from here to a paginated memory model.

One Response to “From Grub to protected mode (1)”

  1. Hey, I love your site. It seems most people don’t really bother writing articles that lack substance nowadays.

Leave a Reply