OSDev.org

The Place to Start for Operating System Developers
It is currently Tue Apr 23, 2024 5:15 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 25 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Setting up GDT breaks code
PostPosted: Tue Oct 21, 2014 8:37 am 
Offline
Member
Member
User avatar

Joined: Fri May 16, 2014 11:50 am
Posts: 38
Location: Bulgaria
I'm at the point where I've set up and loaded my global descriptor table. However, no code past that point gets executed... I assumed it is because I remap the SS and DS registers to 0x10 but it's what it was mentioned in the GDT tutorials. Am I missing something here? Isn't 0x10:0x0000+ BIOS code so why do segments point to that place?

_________________
Practice makes perfect.


Top
 Profile  
 
 Post subject: Re: Setting up GDT breaks code
PostPosted: Tue Oct 21, 2014 8:48 am 
Offline
Member
Member

Joined: Thu May 28, 2009 2:41 pm
Posts: 70
Location: Germany
The BASE address of your segment descriptors is probably set to 0x00000000. That means the segments starts at address 0x00000000.

At 0x10:0x00000000 there is probably the real mode IVT if segment 0x10's base address equals 0x00000000.
So you probably shouldn't jump there after setting up your GDT. You want to jump to your own 32-Bit code:

Code:
; GDT must have been loaded already

jmp 0x10:pm_mode_code

pm_mode_code:
  jmp $


You probably should post some code.


Top
 Profile  
 
 Post subject: Re: Setting up GDT breaks code
PostPosted: Tue Oct 21, 2014 11:58 am 
Offline
Member
Member
User avatar

Joined: Sun Sep 19, 2010 10:05 pm
Posts: 1074
jrhetf4xb wrote:
I'm at the point where I've set up and loaded my global descriptor table. However, no code past that point gets executed... I assumed it is because I remap the SS and DS registers to 0x10 but it's what it was mentioned in the GDT tutorials. Am I missing something here? Isn't 0x10:0x0000+ BIOS code so why do segments point to that place?

Segment 0x10 can be mapped to any physical memory address you want, but mapping it to 0x00000000 is probably the easiest way to get started.

Also, once you jump to a 32-bit code segment, the BIOS is all but useless, so you can (or should) just ignore it. (Just make sure you are avoiding any memory locations marked as RESERVED in your memory map.)

Also, keep in mind that if segment 0x10 is a data segment, then you can't jump to it. You probably have segment 0x08 set up as a code segment, so you should use:
Code:
jmp 0x08:pm_mode_code

_________________
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott


Top
 Profile  
 
 Post subject: Re: Setting up GDT breaks code
PostPosted: Tue Oct 21, 2014 3:42 pm 
Offline
Member
Member
User avatar

Joined: Fri May 16, 2014 11:50 am
Posts: 38
Location: Bulgaria
Don't hang me up if I'm doing something completely wrong...
I assumed I could continue executing some of my code after loading the segments (and GDT).
And the base address is set to 0 because my code jumps to 0x100:0x0000 (caused by boot0, which loaded boot1 there).
And after performing lgdt I do jump to some of my code and try to print, but as you pointed out BIOS doesn't do anything :D I guess that's why I thought it broke my code... But if I can't use the BIOS how am I supposed to load the rest of my kernel? (a bit off-topic question...)
I'm in a bit of a mess right now. If I reload my data segment, would my labels still be accessible in the same location? Say 0x100:0x3A6 for gdt, looking at objdump before loading the binary in a floppy img...


Attachments:
boot1.S [2.67 KiB]
Downloaded 35 times

_________________
Practice makes perfect.
Top
 Profile  
 
 Post subject: Re: Setting up GDT breaks code
PostPosted: Tue Oct 21, 2014 4:00 pm 
Offline
Member
Member

Joined: Thu May 28, 2009 2:41 pm
Posts: 70
Location: Germany
As SpyderTL already said: You must not use BIOS interrupts after switching to 32-Bit protected mode.
In gdt_flush (at least) you use int 0x10 which will jump into 16 bit real mode code or may just crash because you didn't setup an IDT (I'm not sure which one will happen, but in both cases your code crashes)

Did you write this code on your own or did you copy it and just added some lines?
If you copied this than you should probably learn what this code does otherwise you won't make it too far.
If you wrote the code yourself than forget the last paragraph and just remember not to call BIOS interrupts in protected mode ;)


Top
 Profile  
 
 Post subject: Re: Setting up GDT breaks code
PostPosted: Tue Oct 21, 2014 4:13 pm 
Offline
Member
Member
User avatar

Joined: Fri May 16, 2014 11:50 am
Posts: 38
Location: Bulgaria
Right, I get it for the BIOS interrupts. And that starting from 0x10 runs over BIOS code, which basically invalidates the BIOS functions. I just don't understand what happens after I load the GDT...
So far I got it that I set up 4GB overlapping segments for code and data. I store a gdtr 48bit pointer that has the size of the GDT structure (times four because of my four entries), as well as the address where this GDT structure starts in memory. I then load all segment registers to 0x10, and code segment to 0x08, which would mean that all of my data and code starts from 0x10 up to ... 0x7FFFFFFF? What I don't get is what happens to all my variables/labels I've used so far and have stored data into. Do they preserve their addresses? Would I access, say, gdt at 0x13A6 again (0x100:0x3A6 previously)? Is this the point where I enter protected mode? What about loading the kernel and running kmain?

_________________
Practice makes perfect.


Top
 Profile  
 
 Post subject: Re: Setting up GDT breaks code
PostPosted: Tue Oct 21, 2014 6:11 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5143
It sounds like you're confused about what segment registers do.

In real mode (when the computer boots), the value in the segment register is translated to the segment's base address by multiplying it by 16. The segment's limit and other attributes are generally fixed to a particular set of defaults that approximate running code on an 8086.

In protected mode (which you are now trying to use), the value in the segment register is used as an offset into the GDT. The segment's base address, limit, and other attributes are loaded from the GDT.

The part that you seem to be confused about is the base address. In real mode, the base address is clearly indicated by the value in the segment regsiter. (Using 0x10 for a real-mode segment sets the base address to 0x100.) In protected mode, the base address is in the GDT, and the segment register's value is completely unrelated. (In your OS, protected mode segment 0x10 has a base address of 0, but in my OS, protected mode segment 0x10 has a base address of 0x528000.)

As for your labels, the assembler doesn't know when you've changed the base address. As far as it's concerned, your GDT is located at offset 0x03A6, whether you're in real mode or protected mode. For simplicity's sake, I recommend using a base address of 0 in all of your real-mode code as much as possible (set CS, DS, ES, and SS to 0 while in real mode). This way, offsets in both real and protected mode will be relative to the same base address. You will need to modify your linker script for this.


Top
 Profile  
 
 Post subject: Re: Setting up GDT breaks code
PostPosted: Tue Oct 21, 2014 8:04 pm 
Offline
Member
Member

Joined: Sat Feb 27, 2010 8:55 pm
Posts: 147
jrhetf4xb wrote:
Right, I get it for the BIOS interrupts. And that starting from 0x10 runs over BIOS code, which basically invalidates the BIOS functions.

As Octocontrabass pointed out, you're a bit confused about segmentation. (Don't feel bad, a lot of people get confused here!) I want to point out that even if you don't overwrite the IVT, BDA, EDBA, you still can't use the BIOS. For starters, the BIOS is 16bit code, and you're jumping to a 32 bit segment. But that's still not the whole reason; even if you use 16 bit protected mode, you still can't use the BIOS because of how wildly different segmentation works.
jrhetf4xb wrote:
Is this the point where I enter protected mode?

If you're asking if you did enter protected mode, yes, your far jump did that. If you're asking if you should enter protected mode at this point, well...

jrhetf4xb wrote:
What about loading the kernel and running kmain?

One thing I would do before entering protected mode is use the BIOS functions to load the whole kernel, or load at least enough to read the appropriate drive with direct I/O commands.

You should also get a memory map and, if applicable, switch to the desired screen mode.

Technically you don't have to do these things before switching to protected mode, but switching back and forth between PM and RM or using V86 requires a pretty thorough understanding of what you're doing -- I wouldn't recommend it starting off.


Top
 Profile  
 
 Post subject: Re: Setting up GDT breaks code
PostPosted: Wed Oct 22, 2014 5:18 am 
Offline
Member
Member
User avatar

Joined: Fri May 16, 2014 11:50 am
Posts: 38
Location: Bulgaria
Octocontrabass wrote:
In protected mode, the base address is in the GDT, and the segment register's value is completely unrelated.


Octocontrabass wrote:
In protected mode (which you are now trying to use), the value in the segment register is used as an offset into the GDT. The segment's base address, limit, and other attributes are loaded from the GDT.

Ah, right, now it makes sense! It feels so good once you understand it.

Octocontrabass wrote:
As for your labels, the assembler doesn't know when you've changed the base address. As far as it's concerned, your GDT is located at offset 0x03A6, whether you're in real mode or protected mode.

At a later point in my code would it be sane to relocate the GDT to some other address or should I leave it there?

azblue wrote:
I want to point out that even if you don't overwrite the IVT, BDA, EDBA, you still can't use the BIOS.

azblue wrote:
One thing I would do before entering protected mode is use the BIOS functions to load the whole kernel, or load at least enough to read the appropriate drive with direct I/O commands.

You should also get a memory map and, if applicable, switch to the desired screen mode.

I see, thank you!

One thing I'm still confused about is that you keep mentioning I'm entering protected mode, but I thought I'm just preparing for it so far... Intel's manuals (section 9.8 of Vol. 3A) mention that I require a GDT (done so far), IDT, TSS and a code segment to be executed once the mode is entered. And section 9.9.1 outlines the whole process of switching to protected mode, mainly setting CR0 that does the whole serialisation. Wouldn't I be in protected mode once I code all of that?

_________________
Practice makes perfect.


Top
 Profile  
 
 Post subject: Re: Setting up GDT breaks code
PostPosted: Wed Oct 22, 2014 5:33 am 
Offline
Member
Member

Joined: Thu May 28, 2009 2:41 pm
Posts: 70
Location: Germany
Setting up your GDT is preparation, because you need a GDT in PM.
then you set Bit 0 of cr0 to 1 which enables protected mode.
Now your GDT is valid. After far jumping to a code segment defined in your GDT you are in Protected mode and you can execute 32 bit code.

So the far jump is a jump into protected mode. Your protected mode code should be 32 bit code ([BITS 32] in nasm) (except you made a 16 bit code segment in your GDT)

You should also disable interrupts before jumping to PM because otherwise your code will crash as soon as an interrupt occurs because in PM the IDT is necessary for interrupts to work properly. (There's more information about all this in the wiki)


Top
 Profile  
 
 Post subject: Re: Setting up GDT breaks code
PostPosted: Wed Oct 22, 2014 8:01 am 
Offline
Member
Member
User avatar

Joined: Fri May 16, 2014 11:50 am
Posts: 38
Location: Bulgaria
Cjreek wrote:
(except you made a 16 bit code segment in your GDT)

I might have not filled it in properly... Is this how it should be structured to have 32bit segments?

limit_low, base_low, base_middle, access, granularity, base_high
0xFFFF | 0x0000 | 0x00 | 0x9A | 0xCF | 0x00

EDIT: I noticed the GDT doesn't have a limit_high... Is it computed somehow?

_________________
Practice makes perfect.


Top
 Profile  
 
 Post subject: Re: Setting up GDT breaks code
PostPosted: Wed Oct 22, 2014 8:24 am 
Offline
Member
Member
User avatar

Joined: Wed Oct 27, 2004 11:00 pm
Posts: 874
Location: WA
yes there is a "limit_high"

the full limit fields combined are 20 bits

the manuals clearly show 2 segment limit fields in the diagram, and the following in the description:

Intel 3A:4.2 wrote:
Limit field -- (Bits 0 through 15 of the first doubleword and bits 16 through 19 of the second doubleword of a segment descriptor.) Determines the size of the segment, along with the G flag and E flag (for data segments).

_________________
## ---- ----- ------ Intel Manuals
OSdev wiki


Top
 Profile  
 
 Post subject: Re: Setting up GDT breaks code
PostPosted: Wed Oct 22, 2014 10:49 am 
Offline
Member
Member
User avatar

Joined: Fri May 16, 2014 11:50 am
Posts: 38
Location: Bulgaria
Alright, I found it. Now let's just hope that I've set the values correctly :)

_________________
Practice makes perfect.


Top
 Profile  
 
 Post subject: Re: Setting up GDT breaks code
PostPosted: Fri Oct 24, 2014 11:05 am 
Offline
Member
Member
User avatar

Joined: Fri May 16, 2014 11:50 am
Posts: 38
Location: Bulgaria
I've stumbled upon some weird behaviour.
I get a triple fault immediately after I long jump to 0x08:some_label, even though I have disabled interrupts.
The message I get from Bochs' log files is interrupt(): gate descriptor is not valid sys seg, which after some investigation turns out to be related to interrupts, but I have disabled them...
I thought it might have been from my GDT having wrong set-up. Tried reversing endian-ness but still gives me this...

I found a thread on stackoverflow which describes the same problem as mine, however the solution isn't helpful as I do not have problems with far jump addresses: http://stackoverflow.com/questions/1298 ... ected-mode

Here's the output from Bochs:
Code:
00017996185i[BIOS ] Booting from 0000:7c00
00018222607e[CPU0 ] check_cs(0x0008): conforming code seg descriptor dpl > cpl, dpl=3, cpl=0
00018222607e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00018222607e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00018222607i[CPU0 ] CPU is in protected mode (active)
00018222607i[CPU0 ] CS.d_b = 16 bit
00018222607i[CPU0 ] SS.d_b = 16 bit
00018222607i[CPU0 ] EFER   = 0x00000000
00018222607i[CPU0 ] | RAX=0000000060000011  RBX=0000000000000000
00018222607i[CPU0 ] | RCX=0000000000090002  RDX=0000000000000000
00018222607i[CPU0 ] | RSP=000000000000ffff  RBP=0000000000000000
00018222607i[CPU0 ] | RSI=00000000000e0000  RDI=0000000000000002
00018222607i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00018222607i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00018222607i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00018222607i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00018222607i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00018222607i[CPU0 ] | SEG selector     base    limit G D
00018222607i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00018222607i[CPU0 ] |  CS:0500( 0004| 0|  0) 00005000 0000ffff 0 0
00018222607i[CPU0 ] |  DS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00018222607i[CPU0 ] |  SS:9000( 0005| 0|  0) 00090000 0000ffff 0 0
00018222607i[CPU0 ] |  ES:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00018222607i[CPU0 ] |  FS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00018222607i[CPU0 ] |  GS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00018222607i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00018222607i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00018222607i[CPU0 ] | RIP=000000000000004f (000000000000004f)
00018222607i[CPU0 ] | CR0=0x60000011 CR2=0x0000000000000000
00018222607i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00018222607i[CPU0 ] 0x000000000000004f>> jmp far 0008:0554 : EA54050800
00018222607e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00018222607i[SYS  ] bx_pc_system_c::Reset(HARDWARE) called
00018222607i[CPU0 ] cpu hardware reset


And my stage two bootloader code:
Code:
.code16
.section .data
   upper_mem: .word 0, 0, 0, 0
   gdt: .quad 0x0000000000000000, 0x00CF9A000000FFFF, 0x00CF92000000FFFF
   gdtr: .word 0, 0, 0

.section .text
   .globl boot1
   .globl upper_mem /* extern void *upper_mem asm("upper_mem"); */
   .globl gdtr;     /* extern void *gdtr asm("gdtr"); */
   .globl gdt_flush;
   
boot1:
   cli
   
   /* re-set the stack and segments */
   xorw %ax, %ax
   movw %ax, %es
   movw %ax, %ds
   
   movw $0x9000, %ax
   movw %ax, %ss
   movw $0xFFFF, %sp
   
   sti

   /* enable A20 line */
   movw $0x2401, %ax
   int $0x15

   /* load the kernel */
   
   /* set up for protected mode */
   cli
   
   /* install global descriptor table */
  gdt_install:
   movw $23, gdtr /* sizeof (gdt) */
   movl $1, %edi
   movw $0, gdtr(, %edi, 2)
   movl $2, %edi
   movw gdt, %ax
   movw %ax, gdtr(, %edi, 2)
   
   /* apply the global descriptor table */
  gdt_flush:
   /* enter protected mode */
   lgdt gdtr
   movl %cr0, %eax
   orl $1, %eax
   movl %eax, %cr0
   ljmp $0x08, $protected_mode
.code32
protected_mode:
   /* update segments */
   movw $0x10, %ax
   movw %ax, %ds
   movw %ax, %es
   movw %ax, %gs
   movw %ax, %fs
   movw %ax, %ss
   movl $0x0001000, %esp
   
   
   //call kmain
   /* NOTREACHED */
  halt:
   hlt
   jmp halt

_________________
Practice makes perfect.


Top
 Profile  
 
 Post subject: Re: Setting up GDT breaks code
PostPosted: Fri Oct 24, 2014 11:27 am 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4594
Location: Chichester, UK
You are getting a GPF which you aren't handling. (Just a wild guess. ;))


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 25 posts ]  Go to page 1, 2  Next

All times are UTC - 6 hours


Who is online

Users browsing this forum: DotBot [Bot], Majestic-12 [Bot], SemrushBot [Bot] and 117 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