OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Apr 18, 2024 1:06 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: Proctected mode and GDT question
PostPosted: Thu Oct 25, 2018 12:07 pm 
Offline
Member
Member

Joined: Sun Oct 21, 2018 1:37 pm
Posts: 38
Hello,

first post here :-)

First of all I would like to thank you guys for all documentation, tutorials and forum discussions of this site. It is a mine of gold and I am having a blast taking my first steps in the OS dev world.

I am trying to get a grasp on the concepts and techniques around memory while in protected mode.

I have been reading about DGT descriptor and entries, memory layout, meaning and purpose of each of the 8 bytes of every DGT entry, and how to switch to Protected mode.

I have been commenting and executing carefully using bosch a simple example I found that writes a string while in Real mode, using Int 0x10 and then switches to Protected mode, defines one code segment and one data segment (covering the whole 4 Gb each), and then switches to Protected mode and writes another string writing over the VGA RAM area.

Where I am getting lost is in this line:

jmp CODE_SEG:b32

CODE_SEG at that moment is equal to 0x08, which happens to be the GDT entry for the code section. My question/s are:

    I fail to understand why using 0x08:b32 to jump to b32.
    What would be the difference of just jump to b32.
    Is this what we consider a far jump?
    If so, how b32 ended up in a different segment? Is there any relationship of this with the [bits 32] directive?

This is the code (Comments are mine)

Any tip, advise, suggestion will be very welcome !! Thanks in advance !

Code:
; TODO: WRITE VGA RAM  IN REAL MODE!!!!!!!!!!! INVESTIGATE THE OFFSET OF THE MEMORY AND TRY RANDOM STUFF THERE
[bits 16]
[org 0x7c00]
   xchg bx, bx ; magic breakpoint
    jmp 0:kernel_start

gdt_start:

gdt_null:
    dd 0x0 ; 0x00000000 double word, 32 bits, 4 bytes < GDT descriptor 2 + 4 bytes, size + offset
    dd 0x0 ; 0x00000000 double word, 32 bits, 4 bytes ; can be used for a pointer to GDT itself

gdt_code: ;cs should point here, code segment
    dw 0xffff ; 0xFFFF   <- limit low   2 bytes word               0 - 63 (20 bits wide )
    dw 0x0 ; 0x0000      <- base low      2 bytes word
    db 0x0 ; 0x00      <- base middle   1 byte
    db 10011010b ; 0x9A <-  access       1 byte - 1 fix - ring:0 - exec:true  -direction:down
    db 11001111b ; 0xCF <- granularity   1 byte - high = flags, low = limit high, for 4 bits for  20 bits wide limit
    db 0x0 ; 0x00       <-  base high   1 byte                     63 - 63

gdt_data: ;ds, ss, es , fs and gs should point to data descriptor. why??
    dw 0xffff ; 0xFFFF 2 bytes word
    dw 0x0 ; 0x0000 2 bytes word
    db 0x0 ; 0x00 1 byte
    db 10010010b ; 0x92
    db 11001111b ; 0xCF
    db 0x0 ; 0x00 1 byte

gdt_end:

gdt_descriptor: ; there it goes the GDT descriptor 2 bytes size (8 null + 8 per entry = 24 = 0x18)
    dw gdt_end - gdt_start ; 0x18 (with calc, and debug) - Total GDT table size !!
    dd gdt_start ; 0x7c07

CODE_SEG equ gdt_code - gdt_start ; offste from start of the GDT to point CODE section ;0x8
DATA_SEG equ gdt_data - gdt_start ; offset from start of the GDT to point DATA section ;0x10

print:
    pusha
   xchg bx, bx ; magic breakpoint
    mov ah, 14
    mov bh, 0
.loop:
    lodsb
    cmp al, 0
    je .done
    int 0x10
    jmp .loop
.done:
    popa
    ret

uzenet16 db 'Windows 9 !!!', 0
uzenet32 db 'uzenet32', 0

kernel_start:
    mov ax, 0
    mov ss, ax
    mov sp, 0xFFFC ; byte 65,532

    mov ax, 0
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov si, uzenet16
    call print

    cli
   xchg bx, bx ; magic breakpoint
   mov edx,0 ; Bringing to edx the values of the GDT calculations for analysis
   mov edx, gdt_start ; 0x7c07
   mov edx,0
   mov edx, gdt_end ; 0x7c1f
   mov edx,0
   mov edx, CODE_SEG ;0x8
   mov edx,0
   mov edx, DATA_SEG ;0x10
   mov edx,0
   mov edx, gdt_descriptor ; 0x7c1f
   mov edx,0
   mov edx, gdt_data ; 0x7c1f
   mov edx,0
   mov edx, gdt_code ; 0x7c0f

   xchg bx, bx ; magic breakpoint
    lgdt[gdt_descriptor] ; 0x7c1f
   xchg bx, bx ; magic breakpoint
    mov eax, cr0
    or eax, 0x1
    mov cr0, eax
    jmp CODE_SEG:b32

[bits 32]

VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f

print32:
    pusha
    mov edx, VIDEO_MEMORY
.loop:
    mov al, [ebx]
    mov ah, WHITE_ON_BLACK
    cmp al, 0
    je .done
    mov [edx], ax
    add ebx, 1
    add edx, 2
    jmp .loop
.done:
    popa
    ret

b32:
    mov ax, DATA_SEG
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax

    mov ebp, 0x2000
    mov esp, ebp

    mov ebx, uzenet32
    call print32

    jmp $

[SECTION signature start=0x7dfe]
dw 0AA55h


Top
 Profile  
 
 Post subject: Re: Proctected mode and GDT question
PostPosted: Thu Oct 25, 2018 12:34 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
jmp CODE_SEG:b32.Is FAR JMP. It sets both the segment and the offset. After setting the protected flag in CR0 you have to ensure that you are using a 32-bit code selector to be fully in 32-bit protected mode. Selector 0x08 happens to be defined in your code as a Code segment that is 32-bit. After CS is set with the FAR JMP you are now executing instructions as 32-bit. At that point you should be setting the other segment registers (DS, ES etc) to a 32-bit data selector.

The JMP after enabling the protected mode bit in CR0 also has the side effect of clearing the instruction prefetch queue. A CPU that may preload instructions ahead of time may have decoded instructions as 16-bit real mode and wouldn't have been aware that at some point the instructions had to be decoded as 32-bit code. The JMP clears the prefetch queue and forces the processor to start decoding instructions from scratch.


Last edited by MichaelPetch on Fri Oct 26, 2018 6:30 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Proctected mode and GDT question
PostPosted: Thu Oct 25, 2018 2:35 pm 
Offline
Member
Member

Joined: Sun Oct 21, 2018 1:37 pm
Posts: 38
MichaelPetch wrote:
jmp CODE_SEG:b32.Is FAR JMP. It sets both the segment and the offset. After setting the protected flag in CR0 you have to ensure that you are using a 32-bit code selector to be fully in 32-bit protected mode. Selector 0x08 happens to be defined in your code as a Code segment that is 32-bit. After CS is set with the FAR JMP you are now executing instructions as 32-bit. At that point you should be setting the other segment registers (DS, ES etc) to a 32-bit data selector.

The JMP after enabling the protected mode big in CR0 also has the side effect of clearing the instruction prefetch queue. A CPU that may preload instructions ahead of time may have decoded instructions as 16-bit real mode and wouldn't have been aware that at some point the instructions had to be decoded as 32-bit code. The JMP clears the prefetch queue and forces the processor to start decoding instructions from scratch.


Thanks for the answer!, very insightful.

I have just realized what was wrong in my thought process. I was still thinking on segment * 16 + offset (real mode), but after the switch it is 16 bits selector + offset. So the selector 15-3 bits is the index (in my case 0x8, which is 0000_0000_0000_1000b), bit2=0 for GDT, and bit1-0 for ring level, in this case Ring 0.

Thanks again!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot] and 174 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group